#lang racket
;--------------------------------------




(define (safe-/ x y)
  (lambda (ok err)
    (cond [(= 0 y) (err 'division-by-zero)]
          [else (ok (/ x y))])))

(define (print-ok x)
  (printf "print-ok: ~a\n" x))

(define (print-err x)
  (printf "print-err: ~a\n" x))

(define (return x)
  (lambda (ret err)
    (ret x)))

(define (raise x)
  (lambda (ret err)
    (err x)))

(define (bind op1 op2)
  (lambda (ok err)
    (define (my-cont r)
      (define cps-op (op2 r))
      (cps-op ok err))
    (op1 my-cont err)))

(define (run-cps o)
  (o print-ok print-err))

(define (try o1 o2)
  (lambda (ret err)
    (o1 ret (lambda (res) ((o2 res) ret err)))))

;(run-cps (safe-/ 10 1))


(define-syntax do
  (syntax-rules (<-)
    ; Only one monadic-op, return it
    [(_ mexp) mexp]
    ; A binding operation
    [(_ var <- mexp rest ...) (bind mexp (lambda (var) (do rest ...)))]
    ; No binding operator, just ignore the return value
    [(_ mexp rest ...)        (bind mexp (lambda (_) (do rest ...)))]))


;(define o (bind (safe-/ 10 0) (lambda (x) (safe-/ x 2))))
(define o
  (do
    x <- (safe-/ 10 2)
    (raise 'uh-oh)
    y <- (return (display "do we reach here?\n"))
    (return (+ x 10))))


(run-cps o)



















;